package datastructure.utils;

import basics.iconcurrent.EnumSingleton;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Arrays;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author or2
 */
public class SortHelper {

    /**
     * 初始化线程池
     */
    static class SingleTon {
        private static final ThreadPoolExecutor executorService = new ThreadPoolExecutor(2, 3,
                12L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(), EnumSingleton.INSTANCE.getThreadFactoryInstance());

        static {
            executorService.allowCoreThreadTimeOut(true);
        }

        private SingleTon() {
        }

        public static ThreadPoolExecutor getThreadPoolExecutorInstance() {
            return executorService;
        }
    }

    private static final ReentrantLock REENTRANT_LOCK = new ReentrantLock();

    /**
     * 默认反射调用的静态方法的名称
     */
    public static final String DEFAULT_METHOD = "sort";
    /**
     * 数组长度大于该数值时不打印
     */
    private static int maxPrintSize = 10000;

    public static <E extends Comparable> void testArraySorted(Class<?> algo, String methodName, E[] arr) {
//            1. 输出初始数组-元素太多则不输出
        if (arr.length > maxPrintSize) {
        } else {
            synchronized (REENTRANT_LOCK) {
                System.out.println("排序前:");
                Arrays.stream(arr).forEach(Common::print);
                System.out.println();
            }
        }

//        创建缓存线程池，并发执行算法
        Runnable task = () -> {
            try {
                //            2.进行排序 并 ⏲
                Method sort = algo.getMethod(methodName, Comparable[].class);
                long start = System.currentTimeMillis();
                sort.invoke(null, (Object) arr);
                long end = System.currentTimeMillis();
//            3.输出排序后数组
                String algoName = algo.getName();
                if (arr.length > maxPrintSize) {
                } else {
                    synchronized (REENTRANT_LOCK) {
                        System.out.printf("算法 %s->%s 排序后:\n", algoName, methodName);
                        Arrays.stream(arr).forEach(Common::print);
                        System.out.println();
                    }
                }
//            4.输出统计信息
                synchronized (REENTRANT_LOCK) {
                    Duration totalTime = Duration.ofMillis(end - start);
                    IPrint.printWithColor("此次测试算法 %s->%s 共花费时间为: %s", algoName, methodName, totalTime.toString().replace("PT", ""));
                    IPrint.printWithColor("算法规模为:\t" + arr.length);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        };
        Future<?> submit = SingleTon.getThreadPoolExecutorInstance().submit(task);
//        下列代码会导致同步
//        try {
//            submit.get();
//        } catch (InterruptedException | ExecutionException e) {
//            e.printStackTrace();
//        }
//        IPrint.printWithColor(algo.getName() + "->排序后数组是否有序检测: " + Common.test(arr));
    }

    /**
     * 测试数组排序的通用方法, 默认方法名称为 {@code DEFAULT_METHOD = "sort"}
     *
     * @param algo 测试算法所在类
     * @param arr  测试所用数组
     * @param <E>  extends Comparable<E>
     */
    public static <E extends Comparable<E>> void testArraySorted(Class<?> algo, E[] arr) {
        testArraySorted(algo, DEFAULT_METHOD, arr);
    }
}
